home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / BORLAND TURBO / GDIOUT.PAK / GDIOUT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  18.1 KB  |  621 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1995  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:   gdiout.c
  9. //
  10. //  PURPOSE:  Implements the window procedure for the main application
  11. //    window.
  12. //
  13. //  FUNCTIONS:
  14. //    WndProc       - Processes messages for the main window.
  15. //    MsgCommand    - Handle the WM_COMMAND messages for the main window.
  16. //    MsgPaint      - Handles the WM_MESSAGE message by calling 
  17. //                    DrawGDIOutput.
  18. //    MsgGetMinMaxInfo - Sets minimum window size.
  19. //    MsgDestroy    - Handles the WM_DESTROY message by calling 
  20. //                    PostQuitMessage().
  21. //    CmdExit       - Handles the file exit command by calling destory 
  22. //                    window on the main window.
  23. //    DrawGDIOutput - Demonstrates some common and new GDI output APIs.
  24. //
  25. //  COMMENTS:
  26. //    Message dispatch table -
  27. //      For every message to be handled by the main window procedure
  28. //      place the message number and handler function pointer in
  29. //      rgmsd (the message dispatch table).  Place the prototype
  30. //      for the function in globals.h and the definition of the
  31. //      function in the appropriate module.
  32. //    Command dispatch table -
  33. //      For every command to be handled by the main window procedure
  34. //      place the command number and handler function pointer in
  35. //      rgcmd (the command dispatch table).  Place the prototype
  36. //      for the function in globals.h and the definition of the
  37. //      function in the appropriate module.
  38. //    Globals.h Contains the definitions of the structures and dispatch.c
  39. //      contains the functions that use these structures.
  40. //
  41. //
  42.  
  43. #include <windows.h>            // required for all Windows applications
  44. #include <windowsx.h>
  45. #ifdef WIN16
  46. #include "win16ext.h"           // required only for win16 applications
  47. #endif
  48. #include "globals.h"            // prototypes specific to this application
  49. #include "resource.h"
  50.  
  51. // constants
  52. #define NUM_POLYPTS 5
  53. #define NUM_BEZPTS  4
  54. #define NUM_COLORS  6
  55.  
  56. // cell label strings
  57. #ifdef WIN16
  58. char *aszLabel[] = { "SetPixel", "Pen Widths", "Pen Styles", "Polygon",
  59.                      "Polyline", "Arc", "Chord", "Chord",
  60.                      "Pie", "Ellipse", "RoundRect", "Rectangle",
  61.                      "Pie", "Ellipse", "RoundRect", "Rectangle" };
  62. #else
  63. char *aszLabel[] = { "SetPixelV", "Pen Widths", "Pen Styles", "Polygon",
  64.                      "PolyBezier", "Arc", "Chord", "Chord",
  65.                      "Pie", "Ellipse", "RoundRect", "Rectangle",
  66.                      "Pie", "Ellipse", "RoundRect", "Rectangle" };
  67. #endif
  68.  
  69. // some colors to use for pens and brushes
  70. COLORREF acrColor[] = { RGB(255, 0, 0), RGB(0, 255, 0),
  71.                         RGB(0, 0, 255), RGB(0, 255, 255),
  72.                         RGB(255, 0, 255), RGB(255, 255, 0) };
  73.  
  74. // pixel array for SetPixelV demo
  75. int aPixel[] = { 2, 2, 2, 2, 2, 2, 2, 2,
  76.                  2, 0, 0, 0, 0, 0, 0, 2,
  77.                  2, 0, 0, 0, 0, 0, 0, 2,
  78.                  2, 0, 0, 2, 2, 0, 0, 2,
  79.                  2, 0, 0, 2, 2, 0, 0, 2,
  80.                  2, 0, 0, 0, 0, 0, 0, 2,
  81.                  2, 0, 0, 0, 0, 0, 0, 2,
  82.                  2, 2, 2, 2, 2, 2, 2, 2 };
  83.  
  84. // function prototypes
  85. void DrawGDIOutput(HWND, HDC);
  86.  
  87.  
  88. // Main window message table definition.
  89. MSD rgmsd[] =
  90. {
  91.     {WM_COMMAND, MsgCommand},
  92.     {WM_DESTROY, MsgDestroy},
  93.     {WM_PAINT, MsgPaint},
  94.     {WM_GETMINMAXINFO, MsgGetMinMaxInfo}
  95. };
  96.  
  97. MSDI msdiMain =
  98. {
  99.     sizeof(rgmsd) / sizeof(MSD),
  100.     rgmsd,
  101.     edwpWindow
  102. };
  103.  
  104.  
  105. // Main window command table definition.
  106. CMD rgcmd[] =
  107. {
  108.     {IDM_EXIT,  CmdExit},
  109.     {IDM_ABOUT, CmdAbout}
  110. };
  111.  
  112. CMDI cmdiMain =
  113. {
  114.     sizeof(rgcmd) / sizeof(CMD),
  115.     rgcmd,
  116.     edwpWindow
  117. };
  118.  
  119. //
  120. //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
  121. //
  122. //  PURPOSE:  Processes messages for the main window.
  123. //
  124. //  PARAMETERS:
  125. //    hwnd     - window handle
  126. //    uMessage - message number
  127. //    wparam   - additional information (dependant on message number)
  128. //    lparam   - additional information (dependant on message number)
  129. //
  130. //  RETURN VALUE:
  131. //    The return value depends on the message number.  If the message
  132. //    is implemented in the message dispatch table, the return value is
  133. //    the value returned by the message handling function.  Otherwise,
  134. //    the return value is the value returned by the default window procedure.
  135. //
  136. //  COMMENTS:
  137. //    Call the DispMessage() function with the main window's message dispatch
  138. //    information (msdiMain) and the message specific information.
  139. //
  140.  
  141. LRESULT CALLBACK WndProc(HWND   hwnd, 
  142.                          UINT   uMessage, 
  143.                          WPARAM wparam, 
  144.                          LPARAM lparam)
  145. {
  146.     return DispMessage(&msdiMain, hwnd, uMessage, wparam, lparam);
  147. }
  148.  
  149.  
  150. //
  151. //  FUNCTION: MsgCommand(HWND, UINT, WPARAM, LPARAM)
  152. //
  153. //  PURPOSE: Handle the WM_COMMAND messages for the main window.
  154. //
  155. //  PARAMETERS:
  156. //    hwnd     - window handle
  157. //    uMessage - WM_COMMAND (Unused)
  158. //    GET_WM_COMMAND_ID(wparam,lparam)   - Command identifier
  159. //    GET_WM_COMMAND_HWND(wparam,lparam) - Control handle
  160. //
  161. //  RETURN VALUE:
  162. //    The return value depends on the message number.  If the message
  163. //    is implemented in the message dispatch table, the return value is
  164. //    the value returned by the message handling function.  Otherwise,
  165. //    the return value is the value returned by the default window procedure.
  166. //
  167. //  COMMENTS:
  168. //    Call the DispCommand() function with the main window's command dispatch
  169. //    information (cmdiMain) and the command specific information.
  170. //
  171.  
  172. #pragma argsused
  173. LRESULT MsgCommand(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  174. {
  175.     return DispCommand(&cmdiMain, hwnd, wparam, lparam);
  176. }
  177.  
  178.  
  179. //
  180. //  FUNCTION: MsgPaint(HWND, UINT, WPARAM, LPARAM)
  181. //
  182. //  PURPOSE: Paints the client area.
  183. //
  184. //  PARAMETERS:
  185. //
  186. //    hwnd      - Window handle
  187. //    uMessage  - Message number (Unused)
  188. //    wparam    - Extra data     (Unused)
  189. //    lparam    - Extra data     (Unused)
  190. //
  191. //  RETURN VALUE:
  192. //
  193. //    Always returns 0 - Message handled
  194. //
  195. //  COMMENTS:
  196. //   
  197. //
  198.  
  199. #pragma argsused
  200. LRESULT MsgPaint(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  201. {
  202.     PAINTSTRUCT ps;
  203.  
  204.     BeginPaint(hwnd, &ps);
  205.  
  206.     // do the actual output
  207.     DrawGDIOutput(hwnd, ps.hdc);
  208.  
  209.     EndPaint(hwnd, &ps);
  210.     
  211.      return 0;
  212. }
  213.  
  214. //
  215. //  FUNCTION: MsgGetMinMaxInfo(HWND, UINT, WPARAM, LPARAM)
  216. //
  217. //  PURPOSE: Sets minimum window size.
  218. //
  219. //  PARAMETERS:
  220. //
  221. //    hwnd      - Window handle
  222. //    uMessage  - Message number (Unused)
  223. //    wparam    - Extra data     (Unused)
  224. //    lparam    - Address of MINMAXINFO structure
  225. //
  226. //  RETURN VALUE:
  227. //
  228. //    Always returns 0 - Message handled
  229. //
  230. //  COMMENTS:
  231. //
  232. //
  233.  
  234. #pragma argsused
  235. LRESULT MsgGetMinMaxInfo(HWND   hwnd,
  236.                          UINT   uMessage,
  237.                          WPARAM wparam,
  238.                          LPARAM lparam)
  239. {
  240.     static int     cxMin=0;
  241.     static int     cyMin=0;
  242.     MINMAXINFO FAR *lpmmi;
  243.  
  244.     lpmmi = (MINMAXINFO FAR *)lparam;
  245.      if (cxMin == 0 && cyMin == 0)
  246.     {
  247.         HDC        hdc;
  248.         int        i;
  249.         TEXTMETRIC tm;
  250.         SIZE       size;
  251.  
  252.         
  253.         hdc = GetDC(hwnd);
  254.         
  255.         // find minimum allowable window size by finding widest cell label string
  256.         for (i = 0; i < 16; i ++)
  257.         {
  258.                 GetTextExtentPoint(hdc, aszLabel[i], lstrlen(aszLabel[i]), &size);
  259.             cxMin = cyMin = max(cxMin, size.cx);
  260.         }
  261.  
  262.         // add one-character-wide margin
  263.         GetTextMetrics(hdc, &tm);
  264.         cxMin += 2 * tm.tmAveCharWidth;
  265.         cyMin += 2 * tm.tmAveCharWidth;
  266.         
  267.         ReleaseDC(hwnd, hdc);
  268.     }
  269.     lpmmi->ptMinTrackSize.x = 4 * cxMin;
  270.     lpmmi->ptMinTrackSize.y = 4 * cyMin;
  271.  
  272.     return 0;
  273. }
  274.  
  275. //
  276. //  FUNCTION: MsgDestroy(HWND, UINT, WPARAM, LPARAM)
  277. //
  278. //  PURPOSE: Calls PostQuitMessage().
  279. //
  280. //  PARAMETERS:
  281. //
  282. //    hwnd      - Window handle  (Unused)
  283. //    uMessage  - Message number (Unused)
  284. //    wparam    - Extra data     (Unused)
  285. //    lparam    - Extra data     (Unused)
  286. //
  287. //  RETURN VALUE:
  288. //
  289. //    Always returns 0 - Message handled
  290. //
  291. //  COMMENTS:
  292. //
  293. //
  294.  
  295. #pragma argsused
  296. LRESULT MsgDestroy(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  297. {
  298.     PostQuitMessage(0);
  299.     return 0;
  300. }
  301.  
  302. //
  303. //  FUNCTION: CmdExit(HWND, WORD, WORD, HWND)
  304. //
  305. //  PURPOSE: Exit the application.
  306. //
  307. //  PARAMETERS:
  308. //    hwnd     - The window.
  309. //    wCommand - IDM_EXIT (unused)
  310. //    wNotify  - Notification number (unused)
  311. //    hwndCtrl - NULL (unused)
  312. //
  313. //  RETURN VALUE:
  314. //    Always returns 0 - command handled.
  315. //
  316. //  COMMENTS:
  317. //
  318. //
  319.  
  320. #pragma argsused
  321. LRESULT CmdExit(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  322. {
  323.     DestroyWindow(hwnd);
  324.     return 0;
  325. }
  326.  
  327. //
  328. //  FUNCTION: DrawGDIOutput(HWND, HDC)
  329. //
  330. //  PURPOSE: Demonstrates some GDI drawing routines.
  331. //
  332. //  PARAMETERS:
  333. //
  334. //    hwnd      - Window handle
  335. //    hdc       - Device context handle
  336. //
  337. //  RETURN VALUE:
  338. //
  339. //    None.
  340. //
  341. //  COMMENTS:
  342. //   
  343. //
  344.  
  345. void DrawGDIOutput(HWND hwnd, HDC hdc)
  346. {
  347.     RECT       rcClient;        // size of client area
  348.     int        cxCell, cyCell;  // dimensions of each drawing area
  349.     int        nMargin;         // margins for each drawing area
  350.     TEXTMETRIC tm;              // text metrics
  351.     SIZE       size;            // text extents
  352.     int        i, j;            // loop indexes
  353.     int        y;               // vertical line position
  354.     int        nModePrev;       // previous fill mode
  355.     int        nWidth;          // pen width
  356.     int        nLineSpacing;    // vert. spacing between pen style/width lines
  357.     HPEN       hpen, hpenPrev;  // pens
  358.     HBRUSH     hbr, hbrPrev;    // brushes
  359.     HBRUSH     hbrNull;
  360.     POINT      aPolyPts[NUM_POLYPTS];   // Polygon point array
  361.     POINT      aBezPts[NUM_BEZPTS];     // PolyBezier point array
  362.  
  363.     // for non-filled drawing
  364.     hbrNull = GetStockObject(NULL_BRUSH);
  365.  
  366.     // get some metrics for doing our drawing
  367.     GetClientRect(hwnd, &rcClient);
  368.     cxCell = rcClient.right / 4;
  369.     cyCell = rcClient.bottom / 4;
  370.     GetTextMetrics(hdc, &tm);
  371.     nMargin = tm.tmHeight + tm.tmExternalLeading;
  372.  
  373.     // draw cell borders
  374.     for (i = 0; i < 4; i++)
  375.     {
  376.         MoveToEx(hdc, i * cxCell, 0, NULL);
  377.         LineTo(hdc, i * cxCell, rcClient.bottom-1);
  378.         MoveToEx(hdc, 0, i * cyCell, NULL);
  379.         LineTo(hdc, rcClient.right-1, i * cyCell);
  380.     }
  381.     MoveToEx(hdc, rcClient.right-1, 0, NULL);
  382.     LineTo(hdc, rcClient.right-1, rcClient.bottom);
  383.     MoveToEx(hdc, 0, rcClient.bottom-1, NULL);
  384.     LineTo(hdc, rcClient.right, rcClient.bottom-1);
  385.  
  386.     // label each cell
  387.     nModePrev = SetBkMode(hdc, TRANSPARENT);
  388.     for (i = 0; i < 16; i++)
  389.     {
  390.         GetTextExtentPoint(hdc, aszLabel[i], lstrlen(aszLabel[i]), &size);                             
  391.         TextOut(hdc,
  392.                 ((i % 4) * cxCell + (cxCell / 2))-(size.cx / 2),
  393.                 (i / 4 + 1) * cyCell - nMargin,
  394.                 aszLabel[i],
  395.                 lstrlen(aszLabel[i]));
  396.     }
  397.     SetBkMode(hdc, nModePrev);
  398.     
  399.     // SetPixelV
  400.     for (i = 0; i < 8; i++)
  401.     {
  402.         for (j = 0; j < 8; j++)
  403.         {
  404. #ifdef WIN16
  405.             SetPixel(hdc,
  406.                      nMargin + i * ((cxCell - 2 * nMargin) / 7),
  407.                      nMargin + j * ((cyCell - 2 * nMargin) / 7),
  408.                      acrColor[aPixel[i + j * 8]]);
  409. #else
  410.             SetPixelV(hdc,
  411.                       nMargin + i * ((cxCell - 2 * nMargin) / 7),
  412.                       nMargin + j * ((cyCell - 2 * nMargin) / 7),
  413.                       acrColor[aPixel[i + j * 8]]);
  414. #endif
  415.         }
  416.     }
  417.  
  418.     // Pen Widths
  419.     nLineSpacing = (cyCell - 2 * nMargin) / 5;
  420.     for (i = 0, nWidth = 1, y = nMargin;
  421.          i < 5;
  422.          i++, nWidth *= 2, y += nLineSpacing)
  423.     {
  424.         hpen     = CreatePen(PS_SOLID, nWidth, acrColor[i]);
  425.         hpenPrev = SelectObject(hdc, hpen);
  426.         MoveToEx(hdc, cxCell + nMargin, y, NULL);
  427.         LineTo(hdc, 2 * cxCell - nMargin, y);
  428.         SelectObject(hdc, hpenPrev);
  429.         DeleteObject(hpen);
  430.     }
  431.  
  432.     // Pen Styles
  433.     nLineSpacing = (cyCell - 2 * nMargin) / 5;
  434.     nModePrev    = SetBkMode(hdc, TRANSPARENT);
  435.     for (i = 0, y = nMargin; i < 5; i++, y += nLineSpacing)
  436.     {
  437.         // since the pen styles (PS_SOLID, etc.) are zero-based,
  438.         //   we can use the loop index for the pen style
  439.         hpen     = CreatePen(i, 1, acrColor[i]);
  440.         hpenPrev = SelectObject(hdc, hpen);
  441.         MoveToEx(hdc, 2 * cxCell + nMargin, y, NULL);
  442.         LineTo(hdc, 3 * cxCell - nMargin, y);
  443.         SelectObject(hdc, hpenPrev);
  444.         DeleteObject(hpen);
  445.     }
  446.     SetBkMode(hdc, nModePrev);
  447.  
  448.     // Polygon
  449.     aPolyPts[0].x = 3 * cxCell + cxCell / 2;
  450.     aPolyPts[0].y = nMargin;
  451.     aPolyPts[1].x = 4 * cxCell - nMargin - (cxCell - 2 * nMargin) / 5;
  452.     aPolyPts[1].y = cyCell - nMargin;
  453.     aPolyPts[2].x = 3 * cxCell + nMargin + (cxCell - 2 * nMargin) / 8;
  454.     aPolyPts[2].y = nMargin + (cyCell - 2 * nMargin) / 3;
  455.     aPolyPts[3].x = 4 * cxCell - nMargin - (cxCell - 2 * nMargin) / 8;
  456.     aPolyPts[3].y = nMargin + (cyCell - 2 * nMargin) / 3;
  457.     aPolyPts[4].x = 3 * cxCell + nMargin + (cxCell - 2 * nMargin) / 5;
  458.     aPolyPts[4].y = cyCell - nMargin;
  459.     nModePrev  = SetPolyFillMode(hdc, ALTERNATE);
  460.     hbr        = CreateSolidBrush(acrColor[0]);
  461.     hbrPrev    = SelectObject(hdc, hbr);
  462.     Polygon(hdc, aPolyPts, NUM_POLYPTS);
  463.     SetPolyFillMode(hdc, nModePrev);
  464.     SelectObject(hdc, hbrPrev);
  465.     DeleteObject(hbr);
  466.  
  467.     // PolyBezier (WIN32) or Polyline (WIN16)
  468.     aBezPts[0].x = nMargin;
  469.     aBezPts[0].y = 2 * cyCell - cyCell / 2;
  470.     aBezPts[1].x = nMargin + 3 * (cxCell - 2 * nMargin) / 4;
  471.     aBezPts[1].y = cyCell + nMargin;
  472.     aBezPts[2].x = nMargin + (cxCell - 2 * nMargin) / 4;
  473.     aBezPts[2].y = 2 * cyCell - nMargin;
  474.     aBezPts[3].x = cxCell - nMargin;
  475.     aBezPts[3].y = 2 * cyCell - cyCell / 2;
  476. #ifdef WIN16
  477.     Polyline(hdc, aBezPts, NUM_BEZPTS);
  478. #else
  479.     PolyBezier(hdc, aBezPts, NUM_BEZPTS);
  480. #endif
  481.  
  482.     // Arc
  483.     Arc(hdc,
  484.         cxCell + nMargin,
  485.         cyCell + nMargin,
  486.         2 * cxCell - nMargin,
  487.         2 * cyCell - nMargin,
  488.         2 * cxCell,
  489.         2 * cyCell,
  490.         cxCell,
  491.         cyCell);
  492.  
  493.     // Chord
  494.     hbrPrev = SelectObject(hdc, hbrNull);
  495.     Chord(hdc,
  496.           2 * cxCell + nMargin,
  497.           cyCell + nMargin,
  498.           3 * cxCell - nMargin,
  499.           2 * cyCell - nMargin,
  500.           3 * cxCell,
  501.           2 * cyCell,
  502.           2 * cxCell,
  503.           cyCell);
  504.     SelectObject(hdc, hbrPrev);
  505.  
  506.     // filled Chord
  507.     nModePrev = SetBkMode(hdc, TRANSPARENT);
  508.     hbr       = CreateHatchBrush(HS_BDIAGONAL, acrColor[1]);
  509.     hbrPrev   = SelectObject(hdc, hbr);
  510.     Chord(hdc,
  511.           3 * cxCell + nMargin,
  512.           cyCell + nMargin,
  513.           4 * cxCell - nMargin,
  514.           2 * cyCell - nMargin,
  515.           4 * cxCell,
  516.           2 * cyCell,
  517.           3 * cxCell,
  518.           cyCell);
  519.     SelectObject(hdc, hbrPrev);
  520.     DeleteObject(hbr);
  521.     SetBkMode(hdc, nModePrev);
  522.  
  523.     // for the non-filled drawing, we use a NULL brush
  524.     hbrPrev = SelectObject(hdc, hbrNull);    
  525.  
  526.     // Pie
  527.     Pie(hdc,
  528.         nMargin,
  529.         2 * cyCell + nMargin,
  530.         cxCell - nMargin,
  531.         3 * cyCell - nMargin,
  532.         cxCell,
  533.         2 * cyCell + cyCell / 2,
  534.         0,
  535.         2 * cyCell);
  536.  
  537.     // Ellipse
  538.     Ellipse(hdc,
  539.             1 * cxCell + nMargin,
  540.             2 * cyCell + nMargin,
  541.             2 * cxCell - nMargin,
  542.             3 * cyCell - nMargin);
  543.  
  544.     // RoundRect
  545.     RoundRect(hdc,
  546.               2 * cxCell + nMargin,
  547.               2 * cyCell + nMargin,
  548.               3 * cxCell - nMargin,
  549.               3 * cyCell - nMargin,
  550.               2 * nMargin,
  551.               2 * nMargin);
  552.  
  553.     // Rectangle
  554.     Rectangle(hdc,
  555.               3 * cxCell + nMargin,
  556.               2 * cyCell + nMargin,
  557.               4 * cxCell - nMargin,
  558.               3 * cyCell - nMargin);
  559.  
  560.     // done with non-filled drawing, so de-select our NULL brush
  561.     SelectObject(hdc, hbrPrev);
  562.  
  563.     // for hatch-filled drawing, we set the background mode
  564.     //   to TRANSPARENT so the background color shows through
  565.     //   the hatched brush
  566.     nModePrev = SetBkMode(hdc, TRANSPARENT);
  567.  
  568.     // filled Pie
  569.     hbr     = CreateHatchBrush(HS_CROSS, acrColor[2]);
  570.     hbrPrev = SelectObject(hdc, hbr);
  571.     Pie(hdc,
  572.         nMargin,
  573.         3 * cyCell + nMargin,
  574.         cxCell - nMargin,
  575.         4 * cyCell - nMargin,
  576.         cxCell,
  577.         3 * cyCell + cyCell / 2,
  578.         0,
  579.         3 * cyCell);
  580.     SelectObject(hdc, hbrPrev);
  581.     DeleteObject(hbr);
  582.  
  583.     // filled Ellipse
  584.     hbr     = CreateHatchBrush(HS_DIAGCROSS, acrColor[3]);
  585.     hbrPrev = SelectObject(hdc, hbr);
  586.     Ellipse(hdc,
  587.             1 * cxCell + nMargin,
  588.             3 * cyCell + nMargin,
  589.             2 * cxCell - nMargin,
  590.             4 * cyCell - nMargin);
  591.     SelectObject(hdc, hbrPrev);
  592.     DeleteObject(hbr);
  593.  
  594.     // filled Roundrect
  595.     hbr     = CreateHatchBrush(HS_FDIAGONAL, acrColor[4]);
  596.     hbrPrev = SelectObject(hdc, hbr);
  597.     RoundRect(hdc,
  598.               2 * cxCell + nMargin,
  599.               3 * cyCell + nMargin,
  600.               3 * cxCell - nMargin,
  601.               4 * cyCell - nMargin,
  602.               2 * nMargin,
  603.               2 * nMargin);
  604.     SelectObject(hdc, hbrPrev);
  605.     DeleteObject(hbr);
  606.  
  607.     // filled Rectangle
  608.     hbr     = CreateHatchBrush(HS_VERTICAL, acrColor[5]);
  609.     hbrPrev = SelectObject(hdc, hbr);
  610.     Rectangle(hdc,
  611.               3 * cxCell + nMargin,
  612.               3 * cyCell + nMargin,
  613.               4 * cxCell - nMargin,
  614.               4 * cyCell - nMargin);
  615.     SelectObject(hdc, hbrPrev);
  616.     DeleteObject(hbr);
  617.     
  618.     // done with hatch-filled drawing, so restore background mode
  619.     SetBkMode(hdc, nModePrev);
  620. }
  621.